package xyz.zcq.zcqrpc.proxy;

import cn.hutool.core.collection.CollectionUtil;
import xyz.zcq.zcqrpc.RpcApplication;
import xyz.zcq.zcqrpc.config.RpcConfig;
import xyz.zcq.zcqrpc.constant.RpcConstant;
import xyz.zcq.zcqrpc.fault.retry.RetryStrategy;
import xyz.zcq.zcqrpc.fault.retry.RetryStrategyFactory;
import xyz.zcq.zcqrpc.fault.tolerant.TolerantStrategy;
import xyz.zcq.zcqrpc.fault.tolerant.TolerantStrategyFactory;
import xyz.zcq.zcqrpc.loadbalancer.LoadBalancer;
import xyz.zcq.zcqrpc.loadbalancer.LoadBalancerFactory;
import xyz.zcq.zcqrpc.model.RpcRequest;
import xyz.zcq.zcqrpc.model.RpcResponse;
import xyz.zcq.zcqrpc.model.ServiceMetaInfo;
import xyz.zcq.zcqrpc.registry.Registry;
import xyz.zcq.zcqrpc.registry.RegistryFactory;
import xyz.zcq.zcqrpc.server.tcp.VertxTcpClient;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 服务代理（JDK动态代理）
 */
public class ServiceProxy implements InvocationHandler {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 获取RPC配置
        RpcConfig rpcConfig = RpcApplication.getRpcConfig();
        Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getRegistry());
        // 构造RPC请求对象RpcRequest
        RpcRequest rpcRequest = RpcRequest.builder()
                .serviceName(method.getDeclaringClass().getName())
                .methodName(method.getName())
                .parameterTypes(method.getParameterTypes())
                .parameters(args)
                .build();
        // 发送请求，获取响应
        ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
        serviceMetaInfo.setServiceName(method.getDeclaringClass().getName());
        serviceMetaInfo.setServiceVersion(RpcConstant.DEFAULT_SERVER_VERSION);
        List<ServiceMetaInfo> serviceMetaInfoList = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());
        if (CollectionUtil.isEmpty(serviceMetaInfoList)) {
            throw new RuntimeException("暂无服务地址");
        }
//        ServiceMetaInfo selectServiceMetaInfo = serviceMetaInfoList.get(0);
        LoadBalancer loadBalancer = LoadBalancerFactory.getInstance(rpcConfig.getLoadBalancer());
        Map<String, Object> requestMap = new HashMap<>();
        requestMap.put("methodName", rpcRequest.getMethodName());
        ServiceMetaInfo selectServiceMetaInfo = loadBalancer.select(requestMap, serviceMetaInfoList);
//        RpcResponse rpcResponse = VertxTcpClient.doRequest(rpcConfig, rpcRequest, selectServiceMetaInfo);
        RpcResponse rpcResponse;
        try {
            RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(rpcConfig.getRetryStrategy());
            rpcResponse = retryStrategy.doRetry(() ->
                    VertxTcpClient.doRequest(rpcConfig, rpcRequest, selectServiceMetaInfo)
            );
        } catch (Exception e) {
            TolerantStrategy tolerantStrategy = TolerantStrategyFactory.getInstance(rpcConfig.getTolerantStrategy());
            rpcResponse = tolerantStrategy.doTolerant(null, e);
        }

        return rpcResponse.getData();

    }

}
